---
layout: post
date: 2024-11-14
title: "Zig's new declaration literals"
description: "A look at Zig's new declaration literals"
tags: [zig]
---

<p>In the last post, we looked at some of <a href=/Zigs-weird-syntax/>Zig' weirder syntax</a>. Specifically, this line of code:</p>

{% highlight zig %}
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
{% endhighlight %}

<p>Some people pointed out that the code could be improved by doing:</p>

{% highlight zig %}
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .{};
{% endhighlight %}

<p>While this may be an improvement, i think it's rarely used. That is, until now. With the introduction of declaration literals, you can expect to see something <em>similar</em> to the above more often.</p>

<h3 id=enum_literals><a href="#enum_literals" aria-hidden=true>Enum Literals</a></h3>
<p>Zig has a feature called "enum literals", which allows you to use the enum value without specifying the enum type. The type is inferred based on the context. Consider this code:</p>

{% highlight zig %}
const Operation = enum {
    add,
    sub,
    mul,
    div,
};

fn calc(a: i32, b: i32, op: Operation) i32 {
    switch (op) {
        .add => return a + b,
        .sub => return a - b,
        .mul => return a * b,
        .div => return @divTrunc(a, b),
    }
}
{% endhighlight %}

<p>The cases for our <code>switch</code> statement is leveraging enum literals, allowing us to specify <code>.add</code> instead of <code>Operation.add</code> (which is also valid). This also works when calling the function. These are both valid and equivalent:</p>

{% highlight zig %}
_ = calc(100, 20, .div);

_ = calc(100, 20, Operation.div);
{% endhighlight %}

<p>The other place you'll commonly see this is when assigning a value:</p>

{% highlight zig %}
user.state = .disabled;
{% endhighlight %}

<p>There's probably an argument to be made that enum literals hurt readability. In my experience it's generally an improvement. First of all, it's always optional. Secondly, if the meaning of the enum value (i.e. <code>disabled</code> above) isn't clear, it <em>could</em> be an indication that other parts of the statement aren't well named.</p>

<h3 id=declarion_literals><a href="#declarion_literals" aria-hidden=true>Declaration Literals</a></h3>
<p>A month or two ago, declaration literals were added to Zig. This is a generalization of what enum literals are. Using the new declaration literal syntax, our above <code>GeneralPurposeAllocator</code> initialization becomes:</p>

{% highlight zig %}
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
{% endhighlight %}

<p>Notice that instead of initializing the value to <code>.{}</code>, we're using <code>.init</code>. What's <code>.init</code>? It's a declaration defined within <code>GeneralPurposeAllocator(T)</code>. Let's build our own trivial example. Previously, we might have done something like:</p>

{% highlight zig %}
const User = struct {
    id: u32 = 0,
};
{% endhighlight %}

<p>Which could have then been initialized with:</p>

{% highlight zig %}
const user: User = .{};
// or, equivalent
const user = User{};
{% endhighlight %}

<p>We can now add an declaration to <code>User</code> like so:</p>

{% highlight zig %}
const User = struct {
    id: u32,

    pub const init = User{
        .id = 0,
    };
};
{% endhighlight %}

<p>Allowing us to initialize a <code>User</code> with:</p>

{% highlight zig %}
const user: User = .init;
{% endhighlight %}

<p>One benefit of this approach is that we can have multiple declarations. This allows us to have groups of default values behind a meaningful label</p>

{% highlight zig %}
const User = struct {
    pub const init = User{
        .id = 0,
    };

    // This entire User example isn't very "meaningful"
    // It's meant to showcase the behavior without any
    // distraction.
    pub const super = User{
        .id = 9001,
    };
};
{% endhighlight %}

<p>Finally, just like with enum declarations, we can opt to be explicit and use:</p>

{% highlight zig %}
const user: User = User.super;
{% endhighlight %}

<p>But that's a lot more messy with generics, which is one area where declarations literals really shines:</p>

{% highlight zig %}
// this is good
var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;

// this is bad
var gpa: std.heap.GeneralPurposeAllocator(.{}) = std.heap.GeneralPurposeAllocator(.{}).init;
{% endhighlight %}


<h3 id=conclusion><a href="#conclusion" aria-hidden=true>Conclusion</a></h3>
<p>Declaration literals should make variable initialization a little more clear. I'm particularly interested in having different groups of default values under a meaningful label. But, as far as I can tell, the old pattern isn't going away. If you already know Zig, you won't have problems reading / writing code that makes use of both techniques. But for newcomers, I think it's just another (small) difficulty in picking up the language.</p>

<p>Furthermore, using the <code>.{}</code> syntax gives the caller the flexibility to override a default value:</p>

{% highlight zig %}
var gpa = std.heap.GeneralPurposeAllocator(.{}){
    .requested_memory_limit = 1_048_576;
};
{% endhighlight %}

<p>Whereas declaration literals requires setting the field explicitly:</p>

{% highlight zig %}
var gpa = std.heap.GeneralPurposeAllocator(.{}) = .init;
gpa.requested_memory_limit = 1_048_576;
{% endhighlight %}

<p>I think it's still a nice addition to the language, but one of Zig's zen is "Only one obvious way to do things" and, at this point, for me, "obvious" this is not. It isn't obvious which approach I should use in my own structs and which is being used by other structs, including the standard library.</p>
